package me.chenqiang.tre.expression;

import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;

import me.chenqiang.tre.entity.Card;
import me.chenqiang.tre.entity.Device;

/**
 * 用于根据字符串三元组（属性名称、表达式类型、属性值）来创建Expression对象的工厂类。
 */
public class ExpressionFactory {
	/**
	 * 字符串类型的属性名称及对应的取值方法。
	 */
	protected static final Map<String, BiFunction<Card, Device, String>> STRING_PROPERTIES = Map.ofEntries(
			Map.entry("持卡人身份类型", (card, device) -> card.getHolderType()),
			Map.entry("受理终端地点", (card, device) -> device.getPosition()));
	/**
	 * 字符串集合属性名称及对应的取值方法。
	 */
	protected static final Map<String, BiFunction<Card, Device, Collection<String>>> STRING_COLLECTION_PROPERTIES = Map
			.ofEntries(Map.entry("持卡人身份标签", (card, device) -> card.getHolderTags()));
	/**
	 * 整数类型的属性名称及对应的取值方法。
	 */
	protected static final Map<String, BiFunction<Card, Device, Integer>> INTEGER_PROPERTIES = Map
			.ofEntries(Map.entry("受理终端类型", (card, device) -> device.getDeviceType()));

	protected Map<String, BiFunction<String, String, Expression>> creators;

	/**
	 * 
	 * @param splitter 用来将输入字符串处理为字符串集合的方法，如果为null则采用默认的逗号分割。
	 */
	public ExpressionFactory(Function<String, Collection<String>> splitter) {
		this.creators = Map.ofEntries(
				Map.entry(IsExpression.Type.IS.name(),
						(p, v) -> new IsExpression(IsExpression.Type.IS, p, STRING_PROPERTIES.get(p), v)),
				Map.entry(IsExpression.Type.IS_NOT.name(),
						(p, v) -> new IsExpression(IsExpression.Type.IS_NOT, p, STRING_PROPERTIES.get(p), v)),

				Map.entry(InExpression.Type.IN.name(),
						(p, v) -> new InExpression(InExpression.Type.IN, p, STRING_PROPERTIES.get(p),
								splitter == null ? Arrays.asList(v.split(",")) : splitter.apply(v))),
				Map.entry(InExpression.Type.NOT_IN.name(),
						(p, v) -> new InExpression(InExpression.Type.NOT_IN, p, STRING_PROPERTIES.get(p),
								splitter == null ? Arrays.asList(v.split(",")) : splitter.apply(v))),

				Map.entry(HasExpression.Type.HAS.name(),
						(p, v) -> new HasExpression(HasExpression.Type.HAS, p, STRING_COLLECTION_PROPERTIES.get(p), v)),
				Map.entry(HasExpression.Type.HAS_NOT.name(),
						(p, v) -> new HasExpression(HasExpression.Type.HAS_NOT, p, STRING_COLLECTION_PROPERTIES.get(p), v)),

				Map.entry(IntegerExpression.Type.EQ.name(),
						(p, v) -> new IntegerExpression(IntegerExpression.Type.EQ, p, INTEGER_PROPERTIES.get(p),
								Integer.parseInt(v))),
				Map.entry(IntegerExpression.Type.NEQ.name(),
						(p, v) -> new IntegerExpression(IntegerExpression.Type.NEQ, p, INTEGER_PROPERTIES.get(p),
								Integer.parseInt(v))),
				Map.entry(IntegerExpression.Type.GT.name(),
						(p, v) -> new IntegerExpression(IntegerExpression.Type.GT, p, INTEGER_PROPERTIES.get(p),
								Integer.parseInt(v))),
				Map.entry(IntegerExpression.Type.GTE.name(),
						(p, v) -> new IntegerExpression(IntegerExpression.Type.GTE, p, INTEGER_PROPERTIES.get(p),
								Integer.parseInt(v))),
				Map.entry(IntegerExpression.Type.LT.name(),
						(p, v) -> new IntegerExpression(IntegerExpression.Type.LT, p, INTEGER_PROPERTIES.get(p),
								Integer.parseInt(v))),
				Map.entry(IntegerExpression.Type.LTE.name(), (p, v) -> new IntegerExpression(IntegerExpression.Type.LTE,
						p, INTEGER_PROPERTIES.get(p), Integer.parseInt(v))));
	}

	/**
	 * 创建Expression表达式对象
	 * @param property 表达式左侧属性名称，必须是{@link #STRING_PROPERTIES} {@link #STRING_COLLECTION_PROPERTIES} {@link #INTEGER_PROPERTIES} 中有的
	 * @param type 表达式类型，必须与property和value参数类型匹配
	 * @param value 表达式右侧值的字符串形式，必须与表达式右侧值的类型（字符串、字符串集合或整数）匹配
	 * @return
	 */
	public Expression produce(String property, String type, String value) {
		if (!this.creators.containsKey(type)) {
			throw new IllegalArgumentException(String.format("不支持的规则类型：%s", type));
		}
		return this.creators.get(type).apply(property, value);
	}

}
